【アップデート】IoT デバイスへ簡単にコマンドを実行できる!AWS IoT Device Management にコマンド機能がリリースされました
先日、AWS IoT Device management に新しく 「コマンド機能」 がリリースされました。
コマンド機能とは?
一般的に、MQTT プロトコルでデバイスに何らかの処理を指示するコマンドを送る場合、メッセージにコマンド内容を記載しておき、デバイス側でそのメッセージ内容から実施すべきコマンドを解釈して実行することが多いと思います。
AWS IoT Core を利用する場合も基本的には同じ方法になりますが、実際にコマンド(となるメッセージ)を送る場合、次のような点に気をつける必要があります。
- コマンドの送信や実行結果をやり取りする MQTT トピックの指定
- コマンドの実行結果の追跡・管理
- 実行結果を AWS IoT Core(ブローカー) で受けた後の処理
- AWS IoT Core のルール設定やルーティング後の環境構成やデータ処理
- コマンドを送るメッセージ(ペイロード)の形式( JSON など)
今回のアップデートでは、これらの検討事項や設定作業においてユーザー側の作業工数を減らし、より簡単にコマンド実行できるようになりました。
コマンド機能を試す
コマンドの作成
それでは、早速試してみたいと思います。
最初にデバイスに送るコマンドのペイロードを作成します。今回は次のような内容の JSON ファイル(test-payload.json
)を用意しました。
このペイロードの内容が AWS IoT Core からデバイスに Publish されます。
{
"command": "my command",
"option": "my_command_option"
}
次にコンソール上でコマンドを作成します。
AWS IoT Core のコンソール画面に 「コマンド」 という項目が新たに作成されています。このメニューをクリックして 「コマンド」 画面を開きます。
コマンド画面で 「コマンドを作成」 をクリックします。
コマンドID
、表示名
、説明を入力します。
「ペイロードの指定」の箇所で、先ほど作成した JSON ファイル(test-payload.json
)をアップロードします。
ファイル形式はアップロードしたファイルに応じて自動選択されます。意図したものではない場合は手動で指定します。
testCommand
が作成できました。
デバイス側の準備
コマンドを実行すると 「コマンド要求トピック」 という指定のトピックにコマンド内容が Publish されます。デバイス側は、この「コマンド要求トピック」を Subscribe することでコマンド内容を受信します。
コマンド要求トピックの書式は以下のとおりです。
$aws/commands/<devices>/<DeviceID>/executions/<executionId>/request/<PayloadFormat>
今回は、デバイスレジストリに登録済みの blogTestDevice
というデバイスで試すので、次のようになります。<executionId>
はコマンド実行ごとに発行されるユニーク ID なので、<executionId>
はワイルドーカード +
で Subscribe しておきます。
$aws/commands/things/blogTestDevice/executions/+/request/json
検証用にデバイスは用意していないので、デバイスの代わりに MQTT クライアントでコマンドを受け取ってみます。クライアントアプリは「MQTTX」を使っています。(任意のものをご利用ください)
MQTT クライアント上で「コマンド要求トピック」を Subscribe しておきます。
これでデバイス(クライアント)側の準備は以上です。
コマンド実行
準備ができたのでコマンドを実行します。
次の画面ではコマンドを実行するデバイスを指定します。今回は blogTestDevice
を選択します。
タイムアウト値は少し長めに 5 分にしました。(検証のために、後で手動でデバイス側からコマンドステータスを publish するためです。)
この状態でコマンドを実行すると、デバイス(クライアント)上で設定済みのペイロードを受け取ることができました!
ペイロードの他に受信したトピックも分かるので「実行 ID(executionId
)」も確認できます。
本来はこのペイロードに記載されているコマンドをデバイスが解釈・処理して、その結果を AWS IoT Core に返すことになります。今回はデバイス上の処理は「正常に終了したものと仮定」して、結果だけ返すことにします。
レスポンスを返すトピック書式は次のとおりです。
$aws/commands/<devices>/<DeviceID>/executions/<executionId>/response/json
executionId
には、要求トピックでペイロードを受け取った際に確認できている ID を指定します。これで個々の ID に対するステータスを通知することができます。
$aws/commands/things/blogTestDevice/executions/1f3b8743-118c-4b4b-bff0-62781117b6b8/response/json
デバイスからステータス更新するため、次のようなサンプルメッセージを送ります。
これは、LED を赤色に点灯するコマンドを実行した想定で「そのコマンド実行に成功した」ということを示しています。
{
"deviceId": "blogTestDevice",
"executionId": "1f3b8743-118c-4b4b-bff0-62781117b6b8",
"status": "SUCCEEDED",
"statusReason": {
"reasonCode": "LED_TURN_ON_RED",
"reasonDescription": "Command execution succeeded."
}
}
他にもメッセージ書式を変えて試してみたところ、最低限 status
の情報だけあればステータスを更新できるようです。
{
"status": "SUCCEEDED"
}
サンプルメッセージは下記のドキュメントで紹介されています。
デバイスから「成功」というレスポンスを返したので、AWS 側でもステータスが 「成功しました」 となっていることが確認できました。
実行 ID のリンクを開くと詳細を確認できます。
他のサービスとの連携や複雑な処理の実行について
コマンドイベントをサブスクライブすると、コマンド実行のステータスが変更されたときに指定のトピックに通知が行われます。このイベントトピックに対して IoT ルールをセットすることで、AWS Lambda など他のサービスに連携して活用することができます。
- 参考ドキュメント
コマンドトピックでは、個々のコマンドに対して次のトピックにステータスを通知します。
$aws/events/commandExecution/<CommandID>/<CommandExecutionStatus>
<CommandExecutionStatus>
に入るステータスの種類は次のとおりです。
CREATED
IN_PROGRESS
TIMED_OUT
SUCCEEDED
FAILED
REJECTED
公式ドキュメントのURLはこちらです。
例えば、デバイスでのコマンド実行が失敗した時にAmazon SNS で通知を行いたい場合、次のような IoT ルールを作ります。
対象のトピックは $aws/events/commandExecution/+/#
として全てのステータスのイベントを拾いつつ、FAILED
のときだけ SNS にルーティングします。
そのイベントで AWS IoT Core が発行するメッセージサンプルは次の通りです。簡素な内容になっています。
(トピックは $aws/events/commandExecution/<CommandID>/failed
)
{
"executionId": "c300454f-65f9-4c61-b911-a19367ef9d86",
"eventType": "COMMAND_EXECUTION",
"commandArn": "arn:aws:iot:ap-northeast-1:xxxxxxxxxxxx:command/testCommand",
"targetArn": "arn:aws:iot:ap-northeast-1:xxxxxxxxxxxx:thing/blogTestDevice",
"status": "FAILED",
"timestamp": 1732860833314
}
一方で、デバイスから publish されるペイロードの内容そのものを使って、更に複雑な処理を行いたい場合、先ほどデバイスからコマンド結果を Publish したトピックを AWS IoT Core で Subscribe しておけばよさそうに思います。
$aws/commands/<devices>/<DeviceID>/executions/<ExecutionId>/response/<PayloadFormat>
しかし、このトピックは Publish 専用で Subscribe は許可されていませんでした。
デバイスから Publish されたメッセージ全てを取得するには、API でコマンドの実行結果を取得すれば確認できます。( --include-result
オプションを利用します )
下記は AWS CLI の例です。デバイスから送った status
や statusReason
も確認できます。
$ aws iot get-command-execution \
--execution-id 2aabe393-5891-43a7-afb2-9ff8740c6d28 \
--target-arn arn:aws:iot:ap-northeast-1:xxxxxxxxxxxx:thing/blogTestDevice \
--include-result
{
"executionId": "2aabe393-5891-43a7-afb2-9ff8740c6d28",
"commandArn": "arn:aws:iot:ap-northeast-1:xxxxxxxxxxxx:command/testCommand",
"targetArn": "arn:aws:iot:ap-northeast-1:xxxxxxxxxxxx:thing/blogTestDevice",
"status": "TIMED_OUT",
"statusReason": {
"reasonCode": "$NO_RESPONSE_FROM_DEVICE"
},
"result": {},
"executionTimeoutSeconds": 310,
"createdAt": "2024-11-29T11:56:20.070000+09:00",
"lastUpdatedAt": "2024-11-29T12:01:30.147000+09:00",
"startedAt": "2024-11-29T11:56:20.070000+09:00",
"timeToLive": "2025-05-28T11:56:20.070000+09:00"
}
そのため、実行結果のペイロードの詳細な内容にもとづいて後続の処理に連携したい場合は、「コマンド機能」ではなく従来の方法で対応することになると思います。
今回の「コマンド機能」は実行対象として単一のデバイスのみ指定できるものです。このような仕様も踏まえると、あまり複雑な処理ではなく「小規模な範囲で簡易的なコマンドの実行に向いている機能」と捉えるといいかもしれません。
最後に
新しくリリースされた「コマンド機能」をご紹介しました。
似たような機能として IoT Jobs がありますが、「コマンド機能」は手軽にデバイスに命令を送ったり、その結果の管理ができるものでした。
ユースケースに応じて使い分けていただければと思います。
以上です。